package io.renren.modules.yckj.controller;

import io.renren.common.annotation.LogOperation;
import io.renren.common.constant.Constant;
import io.renren.common.page.PageData;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.ExcelUtils;
import io.renren.common.utils.Result;
import io.renren.common.utils.SmsUtil;
import io.renren.common.validator.ValidatorUtils;
import io.renren.common.validator.group.AddGroup;
import io.renren.common.validator.group.DefaultGroup;
import io.renren.common.validator.group.UpdateGroup;
import io.renren.modules.yckj.common.DateTimeUtils;
import io.renren.modules.yckj.dto.AppointDTO;
import io.renren.modules.yckj.dto.MachineDTO;
import io.renren.modules.yckj.dto.OrderDTO;
import io.renren.modules.yckj.dto.TimeDTO;
import io.renren.modules.yckj.entity.TeamRelationEntity;
import io.renren.modules.yckj.enums.status.OrderStatus;
import io.renren.modules.yckj.enums.status.TeamAppointStatus;
import io.renren.modules.yckj.enums.type.BusinessType;
import io.renren.modules.yckj.enums.type.FinishType;
import io.renren.modules.yckj.enums.type.MachineType;
import io.renren.modules.yckj.enums.type.PayWay;
import io.renren.modules.yckj.excel.OrderExcel;
import io.renren.modules.yckj.service.InvoiceLogsService;
import io.renren.modules.yckj.service.MachineService;
import io.renren.modules.yckj.service.OrderService;
import io.renren.modules.yckj.service.TeamRelationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;


/**
 * 预约列表
 *
 * @author Mark sunlightcs@gmail.com
 * @since 1.0.0 2025-04-25
 */
@RestController
@RequestMapping("yckj/order")
@Tag(name = "预约列表")
public class OrderController {
    private static final long TIME_30_MINUTES = 30 * 60 * 1000;

    @Autowired
    private OrderService orderService;

    @Autowired
    private TeamRelationService teamRelationService;

    @Autowired
    private MachineService machineService;

    @Autowired
    private InvoiceLogsService invoiceLogsService;

    @GetMapping("page")
    @Operation(summary = "分页")
    @Parameters({@Parameter(name = Constant.PAGE, description = "当前页码，从1开始", in = ParameterIn.QUERY, required = true, ref = "int"),
            @Parameter(name = Constant.LIMIT, description = "每页显示记录数", in = ParameterIn.QUERY, required = true, ref = "int"),
            @Parameter(name = Constant.ORDER_FIELD, description = "排序字段", in = ParameterIn.QUERY, ref = "String"),
            @Parameter(name = Constant.ORDER, description = "排序方式，可选值(asc、desc)", in = ParameterIn.QUERY, ref = "String")
    })
    @RequiresPermissions("yckj:order:page")
    public Result<PageData<OrderDTO>> page(@RequestParam Map<String, Object> params) {
        PageData<OrderDTO> page = orderService.pageForAdmin(params);
        //调整预约时间显示
        setOrderDTOBookAllTimes(page);
        //求和
        BigDecimal totalNum = orderService.sumActualAmount(params);
        page.setTotalNum(totalNum.toString());
        return new Result<PageData<OrderDTO>>().ok(page);
    }

    @GetMapping("/tech/page")
    @Operation(summary = "分页")
    @Parameters({@Parameter(name = Constant.PAGE, description = "当前页码，从1开始", in = ParameterIn.QUERY, required = true, ref = "int"),
            @Parameter(name = Constant.LIMIT, description = "每页显示记录数", in = ParameterIn.QUERY, required = true, ref = "int"),
            @Parameter(name = Constant.ORDER_FIELD, description = "排序字段", in = ParameterIn.QUERY, ref = "String"),
            @Parameter(name = Constant.ORDER, description = "排序方式，可选值(asc、desc)", in = ParameterIn.QUERY, ref = "String")
    })
    @RequiresPermissions("yckj:order:page")
    public Result<PageData<OrderDTO>> techPage(@RequestParam Map<String, Object> params) {
//        params.put("machineType", MachineType.YES.getCode());
        params.put("bkIdNotNull", true);

        PageData<OrderDTO> page = orderService.page(params);
        //调整预约时间显示
        setOrderDTOBookAllTimes(page);
        //求和
        BigDecimal totalNum = orderService.sumBookTotalTime(params);
        page.setTotalNum(totalNum.toString());
        return new Result<PageData<OrderDTO>>().ok(page);
    }

    @GetMapping("{id}")
    @Operation(summary = "信息")
    @RequiresPermissions("yckj:order:info")
    public Result<OrderDTO> get(@PathVariable("id") Long id) {
        OrderDTO data = orderService.get(id);

        return new Result<OrderDTO>().ok(data);
    }

    @PostMapping
    @Operation(summary = "保存")
    @LogOperation("保存")
    @RequiresPermissions("yckj:order:save")
    public Result save(@RequestBody OrderDTO dto) throws Exception {
        //效验数据
        ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
        dto.setCreateTime(new Date());
        dto.setUpdateTime(new Date());
        return orderService.validatorAppoint(dto);
    }

    @PutMapping
    @Operation(summary = "修改状态")
    @LogOperation("修改状态")
    @RequiresPermissions("yckj:order:update")
    public Result update(@RequestBody OrderDTO dto) throws Exception {
        //效验数据
        ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
        dto.setUpdateTime(new Date());
        OrderDTO orderDTO = orderService.get(dto.getId());
        if (orderDTO != null) {
            TeamRelationEntity teamRelation = teamRelationService.getByTeamIdAndUserId(orderDTO.getTeamId(), orderDTO.getUserId());
            if (dto.getTeamReview() != null && dto.getTeamReview().equals(TeamAppointStatus.REFUSED.getCode())) {
                dto.setStatus(OrderStatus.REFUSED.getCode());
                orderService.teamApprove(orderDTO, dto.getTeamReview(), teamRelation);
            } else {
                orderService.update(dto);
                if (dto.getStatus().equals(OrderStatus.UNCONFIRMED.getCode())) {
                    String time = DateUtils.format(orderDTO.getBookTime(), DateUtils.DATE_PATTERN);
                    if (orderDTO.getBookStartTime() != null) {
                        time = time + " " + orderDTO.getBookStartTime();
                    }
                    SmsUtil.sendSmsToUserTime(orderDTO.getPhone(), orderDTO.getProjectName(), orderDTO.getBookTotalTime().toString(), time);
                }
            }
        }
        return new Result();
    }

    @PutMapping("finish")
    @Operation(summary = "完结订单")
    @LogOperation("完结订单")
    @RequiresPermissions("yckj:order:update")
    public Result finish(@RequestBody OrderDTO dto) throws Exception {
        Result result = new Result().success(0, "订单处理成功");
        OrderDTO dbOrderDTO = orderService.get(dto.getId());
        if (dbOrderDTO != null && dbOrderDTO.getStatus().equals(OrderStatus.WAIT_PAY.getCode())) {
            if (dbOrderDTO.getPayWay().equals(PayWay.WX.getCode())) {
                result = invoiceLogsService.handleOrderFinishedByAdmin(dbOrderDTO.getUserId(), dbOrderDTO.getId(), BusinessType.PAY_ORDER.getCode());
            } else {
                dbOrderDTO.setFinishType(dto.getFinishType());
                //如果实际支付金额为0的时候，不需要判断，直接修改状态
                if (dbOrderDTO.getActualAmount().compareTo(BigDecimal.ZERO) == 0 || dto.getFinishType().equals(FinishType.ONLINE.getCode())) {
                    if (dbOrderDTO.getTeamId() != null && dbOrderDTO.getTeamId() > 0) {
                        //组支付
                        dbOrderDTO.setPayWay(PayWay.TEAM.getCode());
                        orderService.balancePayByUserForTeam(dbOrderDTO.getUserId(), dbOrderDTO);
                    } else {
                        //个人支付
                        dbOrderDTO.setPayWay(PayWay.USER.getCode());
                        orderService.balancePayByUser(dbOrderDTO.getUserId(), dbOrderDTO);
                    }
                    if (dbOrderDTO.getActualAmount().compareTo(BigDecimal.ZERO) > 0) {
                        try {
                            String time = DateUtils.format(dbOrderDTO.getBookTime(), DateUtils.DATE_PATTERN);
                            if (dbOrderDTO.getBookStartTime() != null) {
                                time = time + " " + dbOrderDTO.getBookStartTime();
                            }
                            SmsUtil.sendSmsToUserCharging(dbOrderDTO.getPhone(), dbOrderDTO.getProjectName(), time);
                        } catch (Exception e) {
                            result = new Result().error(1, "短信通知失败");
                        }
                    }
                } else {
                    if (dbOrderDTO.getTeamId() != null && dbOrderDTO.getTeamId() > 0) {
                        //组支付
                        dbOrderDTO.setPayWay(PayWay.TEAM.getCode());
                        orderService.balancePayByUserForTeamByAdmin(dbOrderDTO.getUserId(), dbOrderDTO);
                    } else {
                        //个人支付
                        dbOrderDTO.setPayWay(PayWay.USER.getCode());
                        orderService.balancePayByUserByAdmin(dbOrderDTO.getUserId(), dbOrderDTO);
                    }
                }
            }
        } else {
            result = new Result().error(1, "订单状态不正确，无法完结");
        }
        return result;
    }

    @GetMapping("cancel/{id}")
    @Operation(summary = "取消订单")
    @RequiresPermissions("yckj:order:update")
    public Result cancel(@PathVariable("id") Long id) throws Exception {
        OrderDTO data = orderService.get(id);
        if (data != null) {
            data.setStatus(OrderStatus.CANCEL.getCode());
            data.setUpdateTime(new Date());
            boolean b = orderService.cancel(data);
            if (b) {
                return new Result().success(0, "取消成功");
            } else {
                return new Result().error(1, "取消失败");
            }
        } else {
            return new Result().error(1, "当前订单不存在！");
        }
    }

    @PutMapping("updateAmount")
    @Operation(summary = "修改金额")
    @LogOperation("修改金额")
    @RequiresPermissions("yckj:order:amount")
    public Result updateAmount(@RequestBody OrderDTO dto) throws Exception {
        //效验数据
        if (dto.getActualAmount() != null && dto.getActualAmount().compareTo(BigDecimal.ZERO) > 0) {
            ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
            OrderDTO orderDTO = orderService.get(dto.getId());
            orderService.updateAmount(orderDTO, dto.getActualAmount());
            return new Result();
        } else {
            return new Result().error(1, "输入金额有误！");
        }
    }

    @PutMapping("updateTech")
    @Operation(summary = "修改技术员")
    @LogOperation("修改技术员")
    @RequiresPermissions("yckj:order:tech")
    public Result updateTech(@RequestBody OrderDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
        OrderDTO update = new OrderDTO();
        update.setId(dto.getId());

        //预约日期排序
        if (dto.getBookAllTimes() != null && !dto.getBookAllTimes().isEmpty()) {
            List<Date> dates = new ArrayList<>();
            List<String> sortTimes = new ArrayList<>();
            String[] times = dto.getBookAllTimes().split(",");
            Arrays.stream(times)
                    .forEach(dt -> {
                        Date date = DateUtils.parse(dt, DateUtils.DATE_TIME_PATTERN_16);
                        dates.add(date);
                    });

            // 对日期进行排序
            Collections.sort(dates);
            for (int i = 0; i < dates.size(); i++) {
                Date f = dates.get(i);
                if (i == 0) {
                    update.setBookTime(f);
                    update.setBookStartTime(DateUtils.format(f, DateUtils.DATE_TIME_PATTERN));
                }
                if (i == dates.size() - 1) {
                    update.setBookEndTime(DateUtils.format(f, DateUtils.DATE_TIME_PATTERN));
                }
                sortTimes.add(DateUtils.format(f, DateUtils.DATE_TIME_PATTERN_16));
            }
            update.setBookAllTimes(String.join(",", sortTimes));
        }
        update.setBookTotalTime(dto.getBookTotalTime());
        update.setUpdateTime(new Date());
        orderService.update(update);

        return new Result();
    }

    @PutMapping("updateReports")
    @Operation(summary = "上传报告")
    @LogOperation("上传报告")
    @RequiresPermissions("yckj:order:save")
    public Result updateReports(@RequestBody OrderDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
        dto.setUpdateTime(new Date());
        boolean update = orderService.update(dto);
        if (update) {
            try {
                OrderDTO orderDTO = orderService.get(dto.getId());
                String time = DateUtils.format(orderDTO.getBookTime(), DateUtils.DATE_PATTERN);
                if (orderDTO.getBookStartTime() != null) {
                    time = time + " " + orderDTO.getBookStartTime();
                }
                SmsUtil.sendSmsToUserFinish(orderDTO.getPhone(), orderDTO.getProjectName(), time);
            } catch (Exception e) {
                return new Result().error("短信通知失败");
            }
        }
        return new Result();
    }


//    @DeleteMapping
//    @Operation(summary = "删除")
//    @LogOperation("删除")
//    @RequiresPermissions("yckj:order:delete")
//    public Result delete(@RequestBody Long[] ids) {
//        //效验数据
//        AssertUtils.isArrayEmpty(ids, "id");
//
//        orderService.delete(ids);
//
//        return new Result();
//    }

    @GetMapping("export")
    @Operation(summary = "导出")
    @LogOperation("导出")
    @RequiresPermissions("yckj:order:export")
    public void export(@RequestParam Map<String, Object> params, HttpServletResponse response) throws Exception {
        List<OrderDTO> list = orderService.list(params);
        ExcelUtils.exportExcelToTarget(response, null, "预约列表", list, OrderExcel.class);
    }

    @GetMapping("times")
    @Operation(summary = "根据机器Id,查询已预约时间：machineId可传，可不传，如果传判断当前机器是否需要互斥")
    public Result<List<TimeDTO>> times(@RequestParam Map<String, Object> params) {
        String dateStr = (String) params.get("dateTime");
        params.put("leStatus", OrderStatus.UNCONFIRMED.getCode());
        List<OrderDTO> list = new ArrayList<>();
        String machineId = (String) params.get("machineId");
        if (machineId != null && !machineId.isEmpty()) {
            MachineDTO machineDTO = machineService.get(Long.valueOf(machineId));
            if (machineDTO != null && machineDTO.getType().equals(MachineType.YES.getCode())) {
                list = orderService.list(params);
            }
        } else {
            list = orderService.list(params);
        }
        List<TimeDTO> timeDTOS = DateTimeUtils.getTimeList(dateStr, list);
        return new Result<List<TimeDTO>>().ok(timeDTOS);
    }


    @GetMapping("times/tech")
    @Operation(summary = "根据机器Id,查询已预约时间：machineId可传，可不传，如果传判断当前机器是否需要互斥")
    public Result<List<TimeDTO>> timesTech(@RequestParam Map<String, Object> params) {
        String dateStr = (String) params.get("dateTime");
        List<OrderDTO> list = new ArrayList<>();
        List<TimeDTO> timeDTOS = DateTimeUtils.getTimeList(dateStr, list);
        timeDTOS.forEach(timeDTO -> {
            timeDTO.setStatus(0);
        });
        return new Result<List<TimeDTO>>().ok(timeDTOS);
    }

    @GetMapping("appoints")
    @Operation(summary = "所有预约查询")
    public Result<List<AppointDTO>> appoints(@RequestParam Map<String, Object> params) {
        params.put("leStatus", OrderStatus.UNCONFIRMED.getCode());
        List<OrderDTO> list = orderService.list(params);
        List<AppointDTO> appointDTOS = DateTimeUtils.getAppointList(list);
        return new Result<List<AppointDTO>>().ok(appointDTOS);
    }


    /**
     * 时间分组处理
     *
     * @param dates 日期
     * @return 列表
     */
    private List<List<Date>> groupConsecutiveDates(List<Date> dates) {
        if (dates.isEmpty()) {
            return new ArrayList<>();
        }
        // 1. 对日期进行排序
        Collections.sort(dates);
        List<List<Date>> groups = new ArrayList<>();
        List<Date> currentGroup = new ArrayList<>();
        currentGroup.add(dates.get(0));
        groups.add(currentGroup);

        // 2. 遍历并分组
        for (int i = 1; i < dates.size(); i++) {
            Date prevDate = dates.get(i - 1);
            Date currentDate = dates.get(i);
            // 判断当前日期是否连续
            boolean b = currentDate.getTime() - prevDate.getTime() == TIME_30_MINUTES;
            if (b) {
                currentGroup.add(currentDate);
            } else {
                // 创建新分组
                currentGroup = new ArrayList<>();
                currentGroup.add(currentDate);
                groups.add(currentGroup);
            }
        }
        return groups;
    }

    private void setOrderDTOBookAllTimes(PageData<OrderDTO> page) {
        page.getList().forEach(orderDTO -> {
            List<String> showTimes = new ArrayList<>();
            if (orderDTO.getBookAllTimes() != null && !orderDTO.getBookAllTimes().isEmpty()) {
                String date = DateUtils.format(orderDTO.getBookTime(), DateUtils.DATE_PATTERN);
                showTimes.add(date);
                String[] times = orderDTO.getBookAllTimes().split(",");
                String showTimeFormat = " <span class='order_txt'>%s~%s</span>";
                String firstTime = "", lastTime = "";
                Date firstDate = new Date();
                for (int i = 0; i < times.length; i++) {
                    if (i == 0) {
                        firstDate = DateUtils.parse(times[i], DateUtils.DATE_TIME_PATTERN_16);
                        firstTime = DateUtils.format(firstDate, DateUtils.TIME_PATTERN_4);
                    }
                    if (times.length == 1) {
                        Date lastDate = new Date(firstDate.getTime() + 30 * 60 * 1000);
                        lastTime = DateUtils.format(lastDate, DateUtils.TIME_PATTERN_4);
                    } else {
                        if (i == times.length - 1) {
                            Date lastDate1 = DateUtils.parse(times[i], DateUtils.DATE_TIME_PATTERN_16);
                            Date lastDate2 = new Date(lastDate1.getTime() + 30 * 60 * 1000);
                            lastTime = DateUtils.format(lastDate2, DateUtils.TIME_PATTERN_4);
                        }
                    }
                }
                showTimes.add(String.format(showTimeFormat, firstTime, lastTime));
            }
            orderDTO.setShowTimes(showTimes);
        });
        //调整预约时间显示
//        page.getList().forEach(orderDTO -> {
//            if (orderDTO.getBookAllTimes() != null && !orderDTO.getBookAllTimes().isEmpty()) {
//                List<Date> dates = new ArrayList<>();
//                String[] times = orderDTO.getBookAllTimes().split(",");
//                Arrays.stream(times)
//                        .forEach(dt -> {
//                            Date date = DateUtils.parse(dt, DateUtils.DATE_TIME_PATTERN_16);
//                            dates.add(date);
//                        });
//                if (!dates.isEmpty()) {
//                    List<List<Date>> groups = groupConsecutiveDates(dates);
//                    List<String> showTimes = new ArrayList<>();
//                    groups.forEach(g -> {
//                        Date first = g.get(0);
//                        Date last = new Date(g.get(g.size() - 1).getTime() + TIME_30_MINUTES);
//                        String firstDate = DateUtils.format(first, DateUtils.DATE_PATTERN);
//                        String firstTime = DateUtils.format(first, DateUtils.TIME_PATTERN_4);
//                        String lastDate = DateUtils.format(last, DateUtils.DATE_PATTERN);
//                        String lastTime = DateUtils.format(last, DateUtils.TIME_PATTERN_4);
//                        String showTime = firstDate + " <span class='order_txt'>" + firstTime + "</span> , "
//                                + lastDate + " <span class='order_txt'>" + lastTime + "</span>";
//                        showTimes.add(showTime);
//                    });
//                    orderDTO.setShowTimes(showTimes);
//                }
//            }
//        });
    }
}